parser grammar CParser;

options {
  language = Java;
  output = AST;
  tokenVocab = CLexer;
  ASTLabelType = Arbolito;
}


entrada: (include)* (function_def)+ EOF! ;
include: NUMBERSIGN! INCLUDE^ (LESS! ID (DOT ID)? GREATER! | CADENA); //-> ^(INCLUDE);

//copiado para prueba
//function_def: tipo ID LPARENTHESIS RPARENTHESIS LCURLY RCURLY -> ^(ID);
//tipo: INT | CHAR | FLOAT | DOUBLE | STRING | VOID;

statement: (if_statement | while_statement | var_definition | (expression QUESTION) => if_aritm | action);
action: (asignacion | incdec | RETURN^ (ID | numero)? | function_statement | BREAK) SEMICOLON!;

//definicion funcion 
function_def: tipo ID^ LPARENTHESIS! (params_def | VOID!)? RPARENTHESIS! bloque_stats; // -> ^(tipo ID bloque_stats)

bool: TRUE | FALSE;
numero: (MINUS)? (NUM_INTEGER | NUM_REAL);
incdec: ID (INC | DEC)^; 
asignacion: ID ASSIGN^ valor;
valor: (TRUE | FALSE) => bool | CARACTER | CADENA | valor2;
valor2: (ID LPARENTHESIS) => function_statement | expression;

exp : exp_mult ((PLUS | MINUS)^ exp_mult)* ;
exp_mult : exp_base ((ASTERISK | DIV)^ exp_base)* ;
exp_base : (numero | ID) | LPARENTHESIS! exp RPARENTHESIS!;


bloque_stats: LCURLY! (statement)+ RCURLY!;

//if
if_statement: IF^ ifexp ifbloque (elseif)?;
ifexp: LPARENTHESIS! expression RPARENTHESIS!; 
ifbloque: (bloque_stats | statement); 
elseif: ELSE^ (bloque_stats | statement);

expression: (simple_logic (operator_logico^)*) => exp_logico | exp_comparar;
exp_comparar: exp (operator_comparar^ exp)?; //exp puede derivar en solo ID
exp_logico: simple_logic (operator_logico^ simple_logic)*; 
simple_logic: (NOT)? (bool | ID) | LPARENTHESIS! exp_logico RPARENTHESIS! | function_statement; 
operator_comparar: LESS | GREATER | NOTEQUAL | LESSEQUAL | GREATEQUAL; //< > == <= >= 
operator_logico: AND | OR;

while_statement: WHILE^ LPARENTHESIS! expression RPARENTHESIS! bloque_stats;
if_aritm: expression QUESTION^ if_aritm2;
if_aritm2: valor COLON^ valor SEMICOLON!;

var_definition: tipo^ vardef2;
vardef2: (ASTERISK)? ID (COMMA! ID)* (ASSIGN valor)? SEMICOLON!; //ej.: int * a, b;
tipo: INT^ | CHAR^ | FLOAT^ | DOUBLE^ | STRING^ | VOID^;
   
   
//statement funcion
function_statement: ID^ LPARENTHESIS! (params_statement)? RPARENTHESIS!;
params_statement: param_stat (COMMA! param_stat)*;
param_stat: ID^ (LBRACKET NUM_INTEGER RBRACKET)? | CADENA^; //ej.: yyin = fopen(argv[1], "r");


params_def: def_par (COMMA! def_par)*;
def_par: tipo (ASTERISK)? ID^ (LBRACKET RBRACKET)?;
